package com.ecoolex.chinadutyfree.retailer.admin.graphql;

import java.util.List;
import java.util.stream.Collectors;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;

import com.ecoolex.chinadutyfree.retailer.admin.core.AdminConstant;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoods;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsAfterService;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsBarcode;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsBrand;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsCategory;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsProduct;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsSpec;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsSpecGroup;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsWithBLOBs;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsWithBLOBs.Column;
import com.ecoolex.chinadutyfree.retailer.pojo.AddGoodsDTO;
import com.ecoolex.chinadutyfree.retailer.pojo.EditGoodsDTO;
import com.ecoolex.chinadutyfree.retailer.pojo.EditGoodsProductDTO;
import com.ecoolex.chinadutyfree.retailer.pojo.EditSpecGroupDTO;
import com.ecoolex.chinadutyfree.retailer.pojo.QueryGoodsDTO;
import com.ecoolex.chinadutyfree.retailer.ws.DirectMailGoodsService;
import com.ecoolex.chinadutyfree.retailer.ws.GoodsService;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.util.Assert;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.modularize.api.auth.admin.AdminMemberAuthority;
import com.ecoolex.framework.modularize.api.auth.annotation.AdminAuthoritativeRegister;
import com.ecoolex.framework.modularize.api.service.currency.CurrencyType;
import com.ecoolex.framework.modularize.api.service.currency.CurrencyTypeService;
import com.ecoolex.framework.modularize.api.service.storage.FileSize;
import com.ecoolex.framework.modularize.api.service.storage.MimeType;
import com.ecoolex.framework.modularize.api.service.storage.StorageInfo;
import com.ecoolex.framework.modularize.api.service.storage.StorageService;
import com.ecoolex.framework.modularize.api.service.storage.Upload;
import com.ecoolex.framework.modularize.api.service.storage.UploadLimit;
import com.ecoolex.framework.modularize.api.service.storage.UploadSource;
import com.ecoolex.framework.web.api.graphql2.annotation.GraphQL2Module;
import com.ecoolex.framework.web.api.graphql2.annotation.GraphQL2Module.Type;
import com.ecoolex.framework.web.api.graphql2.annotation.MutationField;
import com.ecoolex.framework.web.api.graphql2.annotation.QueryField;
import com.ecoolex.framework.web.api.graphql2.annotation.Source;
import com.ecoolex.framework.web.api.graphql2.annotation.TypeField;
import com.google.common.collect.Lists;


@GraphQL2Module(type = Type.Admin, description = "商品管理")
@AdminAuthoritativeRegister(parentKey = AdminConstant.AUTH_MODULE_KEY, key = GoodsGraphql.AUTH, name = "商品管理")
public class GoodsGraphql {

	public static final String AUTH = AdminConstant.AUTH_MODULE_KEY + "-GOODS";

	@Reference
	private GoodsService service;
	
	@Reference
	private DirectMailGoodsService directMailGoodsService;

	@Autowired
	private StorageService storageService;

	@Autowired
	private CurrencyTypeService currencyTypeService;

	@TypeField(type = GoodsWithBLOBs.class, field = "brand", description = "商品品牌")
	public GoodsBrand brand(@Source GoodsWithBLOBs source) {
		return service.getBrandById(source.getBrandId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "category", description = "商品分类")
	public GoodsCategory category(@Source GoodsWithBLOBs source) {
		return service.getCategoryById(source.getCategoryId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "currencyType", description = "币种")
	public CurrencyType currencyType(@Source GoodsWithBLOBs source) {
		return currencyTypeService.get(source.getCurrencyType());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "image", description = "商品展示图")
	public StorageInfo image(@Source GoodsWithBLOBs source) {
		return storageService.get(source.getImage());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "afterService", description = "售后模板")
	public GoodsAfterService afterService(@Source GoodsWithBLOBs source) {
		return service.getAfterServiceById(source.getAfterServiceId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "shopwindowList", description = "商品橱窗图列表")
	public List<StorageInfo> shopwindowList(@Source GoodsWithBLOBs source) {
		return service.queryGoodsShopwindowByGoodsId(source.getGoodsId()).stream().map(
			shopwindow -> storageService.get(shopwindow.getImage())).collect(Collectors.toList());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "specGroupList", description = "规格分组列表")
	public List<GoodsSpecGroup> specGroupList(@Source GoodsWithBLOBs source) {
		return service.queryGoodsSpecGroupByGoodsId(source.getGoodsId());
	}

	@TypeField(type = GoodsSpecGroup.class, field = "specList", description = "规格值列表")
	public List<GoodsSpec> specList(@Source GoodsSpecGroup source) {
		return service.queryGoodsSpecByGroupId(source.getSpecGroupId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "productList", description = "商品产品列表")
	public List<GoodsProduct> productList(@Source GoodsWithBLOBs source) {
		return service.queryGoodsProductByGoodsId(source.getGoodsId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "totalStockNumber", description = "总计库存(额定库存数量)")
	public Long totalStockNumber(@Source GoodsWithBLOBs source) {
		return service.sumStockNumberByGoodsId(source.getGoodsId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "totalUsedStockNumber", description = "总计使用库存(销售数量+冻结库存)")
	public Long sumUsedStockNumber(@Source GoodsWithBLOBs source) {
		return service.sumUsedStockNumberByGoodsId(source.getGoodsId());
	}

	@TypeField(type = GoodsWithBLOBs.class, field = "totalSoldNumber", description = "总计销售数量")
	public Long sumSoldNumber(@Source GoodsWithBLOBs source) {
		return service.sumSoldNumberByGoodsId(source.getGoodsId());
	}

	@TypeField(type = GoodsProduct.class, field = "image", description = "产品展示图")
	public StorageInfo image(@Source GoodsProduct source) {
		return storageService.get(source.getImage());
	}

	@TypeField(type = GoodsProduct.class, field = "barcodeList", description = "产品条码列表")
	public List<String> productList(@Source GoodsProduct source) {
		return service.queryGoodsBarcodeByProductId(source.getProductId()).stream().map(
			GoodsBarcode::getBarCode).collect(Collectors.toList());
	}
	
	@TypeField(type = GoodsWithBLOBs.class, field = "associatedDirectMailGoodsCount", description = "关联直邮商品数量")
	public Integer associatedDirectMailGoodsCount(@Source GoodsWithBLOBs source) {
		List<DirectMailGoods> list = directMailGoodsService.getByGoodsId(source.getGoodsId());
		return list.size();
	}

	@MutationField(field = "uploadGoodsImage", description = { "上传商品图片" })
	public StorageInfo uploadGoodsImage(@NonNull Upload request, AdminMemberAuthority user) {
		if (!user.auth(AUTH_ADD) && !user.auth(AUTH_EDIT)) {
            user.notAuthority();
        }
        UploadSource uploadSource = new UploadSource("Goods", "Image");
        UploadLimit uploadLimit = new UploadLimit();
        uploadLimit.setMaxSize(FileSize.MB.byteLength(2));
        uploadLimit.setAllowMimeType(MimeType.IMAGE.commons());

        return storageService.upload(request, uploadSource, uploadLimit);
	}

	@MutationField(field = "uploadGoodsShopwindow", description = { "上传商品橱窗图片" })
	public StorageInfo uploadGoodsShopwindow(@NonNull Upload request, AdminMemberAuthority user) {
		if (!user.auth(AUTH_ADD) && !user.auth(AUTH_EDIT)) {
            user.notAuthority();
        }
        UploadSource uploadSource = new UploadSource("Goods", "Shopwindow");
        UploadLimit uploadLimit = new UploadLimit();
        uploadLimit.setMaxSize(FileSize.MB.byteLength(10));
        uploadLimit.setAllowMimeType(MimeType.IMAGE.commons());

        return storageService.upload(request, uploadSource, uploadLimit);
	}

	private static final String AUTH_GET = AUTH + "-GET";

	@QueryField(field = "goods", description = "获取商品详情")
	@AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_GET, name = "获取商品售后服务详情")
	public GoodsWithBLOBs get(@NonNull Integer goodsId, AdminMemberAuthority user) {
		user.assertLogin();
		return service.getGoodsById(goodsId);
	}

	private static final String AUTH_QUERY = AUTH + "-QUERY";

	@QueryField(field = "goodsList", description = "查询商品列表")
	@AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_QUERY, name = "查询商品列表")
	public Pagination<GoodsWithBLOBs> queryGoods(@NonNull QueryGoodsDTO query, @NonNull Sorting[] sorts, @NonNull Page page, AdminMemberAuthority user) {
		user.assertLogin();
		return service.queryGoods(query, sorts, page);
	}

	private static final String AUTH_ADD = AUTH + "-ADD";

	@MutationField(field = "addGoods", description = "添加商品")
	@AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_ADD, name = "添加商品")
	public GoodsWithBLOBs add(@NonNull AddGoodsDTO add, @NonNull List<String> shopwindowList, @NonNull List<EditSpecGroupDTO> specGroup, AdminMemberAuthority user) {
		user.assertAuth(AUTH_ADD);
		return service.addGoods(add, shopwindowList, specGroup, user.userName());
	}

	private static final String AUTH_EDIT = AUTH + "-EDIT";

	@MutationField(field = "editGoods", description = "编辑商品")
	@AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_EDIT, name = "编辑商品")
	public GoodsWithBLOBs edit(@NonNull EditGoodsDTO edit, @NonNull List<String> shopwindowList, @NonNull List<EditSpecGroupDTO> specGroup, AdminMemberAuthority user) {
		user.assertAuth(AUTH_EDIT);
		GoodsWithBLOBs record = service.getGoodsById(edit.getGoodsId());
		Assert.isTrue(Check.notNull(record), ResultCode.VERIFY.build(1), "商品不存在");
		BeanUtil.copy(edit,
			record,
			Lists.newArrayList(Column.status, Column.deleted, Column.createUser, Column.createTime).stream().map(
				Column::getJavaProperty).toArray(String[]::new));
		return service.updateGoods(record, shopwindowList, specGroup, user.userName());
	}

	@MutationField(field = "uploadGoodsProductImage", description = { "上传商品产品图片" })
	public StorageInfo uploadGoodsProductImage(@NonNull Upload request, AdminMemberAuthority user) {
		if (!user.auth(AUTH_ADD) && !user.auth(AUTH_EDIT)) {
            user.notAuthority();
        }
        UploadSource uploadSource = new UploadSource("GoodsProduct", "Image");
        UploadLimit uploadLimit = new UploadLimit();
        uploadLimit.setMaxSize(FileSize.MB.byteLength(2));
        uploadLimit.setAllowMimeType(MimeType.IMAGE.commons());

        return storageService.upload(request, uploadSource, uploadLimit);
	}

	private static final String AUTH_PRODUCT_EDIT = AUTH + "-PRODUCT-EDIT";

	@MutationField(field = "editGoodsProduct", description = "编辑商品产品")
	@AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_PRODUCT_EDIT, name = "编辑商品产品")
	public GoodsProduct editGoodsProduct(@NonNull EditGoodsProductDTO edit, @NonNull List<String> barcodeList, AdminMemberAuthority user) {
		user.assertAuth(AUTH_PRODUCT_EDIT);
		GoodsProduct record = service.getGoodsProductById(edit.getProductId());
		Assert.isTrue(Check.notNull(record), ResultCode.VERIFY.build(1), "商品产品不存在");
		BeanUtil.copy(edit,
			record,
			Lists.newArrayList(GoodsProduct.Column.goodsId,
				GoodsProduct.Column.specIds,
				GoodsProduct.Column.specNames,
				GoodsProduct.Column.specSorting,
				GoodsProduct.Column.usedStockNumber,
				GoodsProduct.Column.soldNumber,
				GoodsProduct.Column.status,
				GoodsProduct.Column.deleted,
				GoodsProduct.Column.createUser,
				GoodsProduct.Column.createTime).stream().map(GoodsProduct.Column::getJavaProperty).toArray(
					String[]::new));
		return service.updateGoodsProduct(record, barcodeList, user.userName());
	}

	private static final String AUTH_DEL = AUTH + "-DEL";

	@MutationField(field = "delGoods", description = "删除商品")
	@AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_DEL, name = "删除商品")
	public boolean del(@NonNull Integer goodsId, AdminMemberAuthority user) {
		user.assertAuth(AUTH_DEL);
		GoodsWithBLOBs record = service.getGoodsById(goodsId);
		Assert.isTrue(Check.notNull(record), ResultCode.VERIFY.build(1), "商品不存在");
		service.deleteGoods(record, user.userName());
		return true;
	}
}
